{
Version 0.2.3 stable
Made by Marcin Mielniczuk in 2010
License: GNU GPL v3 (open source)
Contact e-mail address: marlinuxsoft@linux.pl
Documentation coming soon... :)
Compilations are planned for 3 most popular operating systems: Linux, Windows and Mac OS X. If you use other system, compile by yourself and/or write to me.
}
program Multicryptix;
uses
	crt;
type
	switch = 0..3; //more ain't necessary ;)
const
	n : string = #10 + #13; //new line
	isWhat1 : switch = 0;
	isWhat2 : switch = 0;
		{
		0 - not a letter or number
		1 - small letter
		2 - capital letter
		3 - number
		}
	result : string = '';
var
	text, key, keySave, choice, todo : string;
	ende : string[2];
	char1, char2, charResult : char;
	position, length1, length2 : word;
	char1_ascii, char2_ascii, charResult_ascii, inputY : shortint;
	correct : boolean;

procedure void(input : string);
	begin
	if (input = '') then halt;
	end;
procedure request(x : string);
	begin
	writeln('Insert text ', x, ' with numbers, English letters and puntuation chars only.', n, 'Other chars will not be encrypted.');
	inputY := wherey + 1; //one line space under the written text
	gotoxy(1, inputY);
	end;
function isWhat(src : shortint) : switch;
	begin
	if (src >= 48) and (src <= 57) then isWhat := 3 //number
	else if (src >= 65) and (src <= 90) then isWhat := 2 //small letter
	else if (src >= 97) and (src <= 122) then isWhat := 1 //caps
	else isWhat := 0;
	end;
function charNumber(src : shortint; isWhat : switch) : shortint;
	begin
	case isWhat of //makes the number of letter in alphabet
		1 : charNumber := src - 96;
		2 : charNumber := src - 64;
		3 : charNumber := src - 48;
		end;
	end;
function backToAscii(src : shortint; isWhat : switch) : shortint;
	begin
	case isWhat of //returns to ascii so that program can write it ;)
		2 : backToAscii := src + 64;
		3 : backToAscii := src + 48;
		else backToAscii := src + 96;
		end;
	end;
function isCorrect(src : string) : boolean;
	var
		lgth, n, ascii : byte;
	begin
	isCorrect := true; //by default i think it's true, i've got no persecution mania ;)
	lgth := length(src);
		for n := 1 to lgth do 
			begin
			ascii := ord(src[n]);
			if (ascii < 32) and (isCorrect = true) then isCorrect := false; //if it's true, doesn't change
			end;
	end;
function doCorrect(x : string; correctSrc : boolean) : string;
	begin
			clrscr;
			writeln('The text you have given contains unallowed chars(written with the ctrl key).');
			request(x);
			readln(doCorrect);
	end;


function getText() : string;
	begin
	todo := 'to ' + ende + 'crypt'; //it's odd, but without it it doesn't work; ende - as the name "en-" or "de-"
	request(todo);
	readln(getText);
	correct := isCorrect(getText); //check if it's correct
	while (correct = false) do //so the user cannot defeat me! ;)
		begin
		getText := doCorrect(todo, correct);
		correct := isCorrect(getText);
		end;
	if (getText = '') then begin clrscr; halt; end; //end of play
	end;

function getKey() : string; //as above
	begin
	request('key');
	readln(getKey);
	correct := isCorrect(getKey);
	while (correct = false) do
		begin
		getKey := doCorrect('key', correct);
		correct := isCorrect(getKey);
		end;
	if (getKey = '') then begin clrscr; halt; end;
	end;

procedure expandKey(); //the key cannot be shorter than text
	begin
	length1 := length(text);
	length2 := length(key);
	keySave := key;
	while length1 > length2 do 
		begin
		key := key + keySave;
		length2 := length(key);
		end;
	end;

function vigenere_decrypt() : string;
	begin
	vigenere_decrypt := ''; //without it i got trash before ;)
		for position := 1 to length1 do //for every char
			begin
			char1 := text[position]; //getting the char
			char2 := key[position];
			char1_ascii := ord(char1); //the ascii number
			char2_ascii := ord(char2);
			isWhat1 := isWhat(char1_ascii); //and finding out what is it
			isWhat2 := isWhat(char2_ascii);
			if isWhat2 = 0 then
				begin
				clrscr;
				writeln('Hey! Key must contain letters and numbers only!!!'); //and if the user's gone too far...
				key := getKey();
				expandKey();
				vigenere_decrypt := vigenere_decrypt();
				clrscr;
				end;
			if isWhat1 = 0 then vigenere_decrypt := vigenere_decrypt + char1 //for example space, comma
				else //letter or number
					begin
					char1_ascii := charNumber(char1_ascii, isWhat1); // to the number in alphabet
					char2_ascii := charNumber(char2_ascii, isWhat2);
					charResult_ascii := char1_ascii - char2_ascii + 1;
					if charResult_ascii < 1 then // may be out of range
						begin
						if (isWhat1 = 1) or (isWhat1 = 2) then charResult_ascii := charResult_ascii + 26 //letter
						else if (isWhat1 = 3) then charResult_ascii := charResult_ascii + 10; //and digit can't be bigger than 9...
						end;
					charResult_ascii := backToAscii(charResult_ascii, isWhat1);
					charResult := chr(charResult_ascii); //char of ascii number
					vigenere_decrypt := vigenere_decrypt + charResult;
					end;
				end;
			end;

function vigenere_encrypt() : string; //as above
	begin
		vigenere_encrypt := '';
		for position := 1 to length1 do
			begin
			char1 := text[position];
			char2 := key[position];
			char1_ascii := ord(char1);
			char2_ascii := ord(char2);
			isWhat1 := isWhat(char1_ascii);
			isWhat2 := isWhat(char2_ascii);
			if isWhat2 = 0 then
				begin
				clrscr;
				writeln('Hey! Key must contain letters and numbers only!!!');
				key := getKey();
				expandKey();
				vigenere_encrypt := vigenere_encrypt();
				clrscr;
				end;
			if isWhat1 = 0 then vigenere_encrypt := vigenere_encrypt + char1
				else
					begin
					char1_ascii := charNumber(char1_ascii, isWhat1);
					char2_ascii := charNumber(char2_ascii, isWhat2);
					charResult_ascii := char1_ascii + char2_ascii - 1;
					if charResult_ascii > 26 then if (isWhat1 = 1) or (isWhat1 = 2) then charResult_ascii := charResult_ascii - 26;
					if charResult_ascii > 9 then if (isWhat1 = 3) then charResult_ascii := charResult_ascii - 10;
					charResult_ascii := backToAscii(charResult_ascii, isWhat1);
					charResult := chr(charResult_ascii);
					vigenere_encrypt := vigenere_encrypt + charResult;
					end;
			end;
		end;

procedure vigenere();
	begin
	if choice = '1' then ende := 'en' //en- or decrypt
	else ende := 'de';
	clrscr;
	text := getText(); //getting data
	clrscr;
	key := getKey();
	clrscr;	
	expandKey();
	if choice = '1' then result := vigenere_encrypt() // and doing what's to be done
	else result := vigenere_decrypt();
	end;

begin
	clrscr;
	writeln('Do you want to encrypt or decrypt?', n, n, ' 1 - encrypt', n, ' 2 - decrypt', n, ' anything else - exit');
	inputY := wherey + 1;
	gotoxy(1, inputY);
	readln(choice);
	if (choice <> '1') and (choice <> '2') then
		begin
		clrscr;
		halt;
		end;
	vigenere();
	writeln('The ', ende, 'crypted text is:', n, result); //yes, that's nearly end
	inputY := wherey + 1;
	gotoxy(1, inputY);
	writeln('Press any key to quit...');
	repeat until keypressed;
	clrscr;
end.
